import subprocess

import boto3
import uuid
import os
import time

import requests
from urllib.parse import urlparse

import urllib3
from PIL import Image, ImageOps
from botocore.exceptions import ClientError
from requests import RequestException
from urllib3.exceptions import InsecureRequestWarning

# 禁用警告
urllib3.disable_warnings(InsecureRequestWarning)

# aws s3
AWS_ACCESS_KEY_ID = 'AKIAQDCRVXI73QBBWRHN'
AWS_SECRET_ACCESS_KEY = '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'
AWS_BUCKET_NAME = 'photo.istorage-cloud.com'
REGION_NAME = 'us-west-2'
s3_session = boto3.Session(
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
    region_name=REGION_NAME
).client('s3')

# cloudflare r2
R2_AccessKeyID = "100fbdd6edb502db068dbd43635b8fec"
R2_SecretAccessKey = "703b037283bda5377241359ed81f1c1ca3a0c84031074a1a4282fd9a03e9a383"
R2_AccountId = "c50d5e3d3a0880da2ec9263ee5b35014"
client_sessions = boto3.client(
    service_name="s3",
    endpoint_url='https://{}.r2.cloudflarestorage.com'.format(R2_AccountId),
    aws_access_key_id=R2_AccessKeyID,
    aws_secret_access_key=R2_SecretAccessKey,
    region_name="auto"
)


def upload_login_or_visitor(complete_file_path, s3_prefixes_path, serviceName="s3", bucketName=None):
    currTime = time.strftime('%Y-%m-%d', time.localtime(time.time()))
    uid = str(uuid.uuid4())
    spUid = ''.join(uid.split('-'))
    file_basename = os.path.basename(complete_file_path)
    print(file_basename)
    if s3_prefixes_path[0] == '/':
        # 移除首个 / 符号
        s3_prefixes_path = s3_prefixes_path[1:]
    file_name = s3_prefixes_path + '/' + currTime + '/' + spUid + '/' + file_basename
    if serviceName == "s3":
        session = s3_session
        BUCKET_NAME = AWS_BUCKET_NAME
    else:
        BUCKET_NAME = bucketName
        session = client_sessions
    try:
        session.upload_file(complete_file_path, BUCKET_NAME, file_name)
    except ClientError as e:
        print(e)
        return None
    return file_name


def upload_with_format_handling(
        new_file_path: str,
        original_key: str = None,  # 原S3文件的key（用于判断格式是否变更）
        s3_prefixes_path: str = "",  # 路径前缀（格式不变且无原key时使用）
        service_name: str = "s3",
        bucket_name: str = None
):
    """
    上传文件到S3，根据新旧文件格式是否一致决定操作：
    - 格式不变：覆盖原key（original_key）
    - 格式改变：生成新key（保留路径，更新扩展名）
    - 无原key：按原有规则生成新key
    """
    # 1. 提取新文件的格式（扩展名）
    new_file_ext = os.path.splitext(new_file_path)[1].lower()  # 如 .png .jpg
    if not new_file_ext:
        raise ValueError("新文件没有扩展名，无法判断格式")

    # 2. 处理原key（判断格式是否变更）
    target_key = None
    if original_key:
        # 提取原key的格式（扩展名）
        original_ext = os.path.splitext(original_key)[1].lower()

        if new_file_ext == original_ext:
            # 格式不变：直接使用原key覆盖
            target_key = original_key
            print(f"格式未变更（{original_ext}），将覆盖原key：{target_key}")
        else:
            # 格式改变：生成新key（替换扩展名，保留路径）
            original_key_without_ext = os.path.splitext(original_key)[0]
            target_key = f"{original_key_without_ext}{new_file_ext}"
            print(f"格式已变更（{original_ext}→{new_file_ext}），将使用新key：{target_key}")

    # 3. 无原key时：按原有规则生成新key（兼容原逻辑）
    if not target_key:
        currTime = time.strftime('%Y-%m-%d', time.localtime())
        uid = str(uuid.uuid4())
        spUid = ''.join(uid.split('-'))
        file_basename = os.path.basename(new_file_path)

        # 处理前缀路径的斜杠
        if s3_prefixes_path.startswith('/'):
            s3_prefixes_path = s3_prefixes_path[1:]

        target_key = f"{s3_prefixes_path}/{currTime}/{spUid}/{file_basename}"
        print(f"无原key，生成新key：{target_key}")

    # 4. 选择存储服务和桶（与原逻辑一致）
    if service_name == "s3":
        session = s3_session
        bucket = AWS_BUCKET_NAME
    else:
        session = client_sessions
        bucket = bucket_name

    # 5. 执行上传
    try:
        session.upload_file(new_file_path, bucket, target_key)
        print(f"上传成功，最终key：{target_key}")
        return True, target_key
    except ClientError as e:
        print(f"上传失败：{str(e)}")
        return False, None


def download_video(url, save_path, max_retries=2):
    """
    下载单张图片，支持重试机制
    """
    retries = 0
    while retries < max_retries:
        try:
            response = requests.get(url, stream=True, verify=False)
            if response.status_code == 200:
                # 检查文件是否已存在，如果存在则删除
                if os.path.exists(save_path):
                    os.remove(save_path)
                # 写入文件
                with open(save_path, 'wb') as f:
                    for chunk in response.iter_content(chunk_size=8192):
                        if chunk:
                            f.write(chunk)
                print(f"视频已下载：{save_path}")
                return True
            else:
                print(f"下载失败，状态码：{response.status_code}")
                retries += 1
        except PermissionError:
            print(f"权限错误：无法写入文件 {save_path}，请检查文件权限或关闭占用程序。")
            retries += 1
        except Exception as e:
            print(f"发生错误：{e}")
            retries += 1
    print(f"下载视频失败，已达到最大重试次数 ：{max_retries}")
    return False


def download_image(url, save_path, max_retries=2):
    """
    使用 wget 下载单张图片，支持重试机制
    """
    retries = 0
    while retries < max_retries:
        try:
            if not os.path.exists(save_path):
                # 确保目标目录存在
                save_dir = os.path.dirname(save_path)
                if save_dir:
                    os.makedirs(save_dir, exist_ok=True)

            # 使用 wget 命令行工具下载图片
            command = [
                "wget",
                "-c",  # 断点续传
                "-t", "3",  # 最多重试 3 次
                "-T", "10",  # 单次 I/O 超时 30 s
                "--retry-connrefused",  # 碰到拒绝连接也重试
                "--waitretry=1",  # 重试间隔 1 s
                "-O", save_path,  # 输出文件
                url
            ]
            result = subprocess.run(command, capture_output=True, text=True)

            # 检查命令执行结果
            if result.returncode == 0:
                print(f"图片已下载：{save_path}")
                return True
            else:
                # 检查是否是404错误，如果是则直接返回失败，不重试
                if "404" in result.stderr:
                    print(f"资源不存在(404)，停止重试：{url}")
                    return False
                print(f"wget下载失败，错误信息：{result.stderr}")
                retries += 1
        except PermissionError:
            print(f"权限错误：无法写入文件 {save_path}，请检查文件权限或关闭占用程序。")
            retries += 1
        except Exception as e:
            print(f"发生错误：{e}")
            retries += 1

    return False


def download_request_image(url, save_path, max_retries=2):
    """
    使用 requests 下载单张图片，支持重试机制
    参数:
        url: 图片URL
        save_path: 本地保存路径（含文件名）
        max_retries: 最大重试次数
    返回:
        成功返回True，失败返回False
    """
    # 设置请求头，模拟浏览器行为，避免被反爬拦截
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
        "Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
        "Accept-Encoding": "gzip, deflate, br"
    }

    retries = 0
    while retries <= max_retries:  # 包含初始尝试+max_retries次重试
        try:
            # 检查文件是否已存在，存在则删除（避免残留旧文件）
            if os.path.exists(save_path):
                os.remove(save_path)
                print(f"已删除旧文件：{save_path}")

            # 发送GET请求， stream=True 支持流式下载（适合大文件）
            with requests.get(url, headers=headers, stream=True, timeout=30) as response:
                # 检查HTTP状态码（200表示成功）
                response.raise_for_status()
                # 验证响应内容是否为图片
                content_type = response.headers.get("Content-Type", "")
                if not content_type.startswith("image/"):
                    print(f"错误：URL返回的不是图片（Content-Type: {content_type}）")
                    retries += 1
                    continue
                # 分块写入文件（避免一次性加载大文件到内存）
                with open(save_path, "wb") as f:
                    for chunk in response.iter_content(chunk_size=1024 * 1024):  # 1MB/块
                        if chunk:  # 过滤空块
                            f.write(chunk)

                print(f"图片下载成功：{save_path}")
                return True

        except RequestException as e:
            # 捕获所有requests相关异常（连接超时、HTTP错误等）
            print(f"下载失败（第{retries + 1}次尝试）：{str(e)}")
            retries += 1
        except PermissionError:
            print(f"权限错误：无法写入文件 {save_path}，请检查权限")
            return False  # 权限错误无需重试
        except Exception as e:
            # 捕获其他意外错误（如文件操作错误）
            print(f"发生错误（第{retries + 1}次尝试）：{str(e)}")
            retries += 1

    print(f"达到最大重试次数（{max_retries + 1}次），下载失败")
    return False


def download_single_image(url, save_path):
    # 确保保存路径的目录存在
    last_slash_index = save_path.rfind('/')
    if last_slash_index > -1:
        save_path_dir = save_path[:save_path.rfind('/')]
        if len(save_path_dir) > 0:
            os.makedirs(save_path_dir, exist_ok=True)

    # 首先尝试使用 wget 下载
    print(f"尝试使用 wget 下载: {url}")
    url = url + '?cache=' + str(time.time())
    success = download_image(url, save_path, max_retries=2)

    # 如果 wget 下载失败，则尝试使用 requests 下载
    if not success:
        print(f"wget 下载失败，尝试使用 requests 下载: {url}")
        success = download_request_image(url, save_path, max_retries=1)

    if success:
        print(f"下载完成: {save_path}")
    else:
        print(f"所有下载方式都失败: {url}")

    return success


def download_single_video(url, save_path):
    last_slash_index = save_path.rfind('/')
    if last_slash_index > -1:
        save_path_dir = save_path[:save_path.rfind('/')]
        if len(save_path_dir) > 0:
            os.makedirs(save_path_dir, exist_ok=True)
    # 下载视频
    return download_video(url, save_path)


def download_file(key, donwload_Path, serviceName="s3", bucketName=None):
    try:
        print(serviceName, bucketName)
        if serviceName == "s3":
            session = s3_session
            BUCKET_NAME = AWS_BUCKET_NAME
        else:
            if bucketName == "istorage-cloud":
                image_url = "https://assets.{}.com/{}".format(bucketName, key)
            else:
                image_url = "https://assets.{}.cloud/{}".format(bucketName, key)  # 替换为实际图片URL
            if download_single_image(image_url, donwload_Path):
                print("下载完成")
                return True, None
            else:
                session = client_sessions
                BUCKET_NAME = bucketName
        session.download_file(BUCKET_NAME, key, donwload_Path)

        return True, None
    except Exception as e:
        # print(e)
        return False, str(e)


def get_url(key, serviceName="s3", bucketName=None):
    try:
        print(serviceName, bucketName)
        if serviceName == "s3":
            bucketName = AWS_BUCKET_NAME
            image_url = "https://{}/{}".format(bucketName, key)
        else:
            if bucketName == "istorage-cloud":
                image_url = "https://assets.{}.com/{}".format(bucketName, key)
            else:
                image_url = "https://assets.{}.cloud/{}".format(bucketName, key)  # 替换为实际图片URL

        return image_url
    except Exception as e:
        return False,


def set_logging(msg):
    # 创建日志目录
    loginfos = os.path.dirname(os.path.abspath("./logs"))
    logfile_path = os.path.join(loginfos, "logs")
    if not os.path.exists(logfile_path):
        os.makedirs(logfile_path)

    # 配置日志处理器以进行定时轮转
    template = "runtime_{date}.log"
    formatted_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
    formatted_string = template.format(date=formatted_date)
    logfile_path = os.path.join(logfile_path, formatted_string)

    with open(logfile_path, 'a') as f:
        f.write(f"{time.strftime('%Y-%m-%d %H:%M:%S %p')} | {msg}\n")
    return
